//---------------------------------------------------------------------------
//
// gaussdb SPQ Optimizer
//
//    Copyright (C) 2021, HuaWei Group Holding Limited
//
//---------------------------------------------------------------------------

#include "naucrates/dxl/parser/CParseHandlerShareIndexScan.h"

#include "naucrates/dxl/operators/CDXLOperatorFactory.h"
#include "naucrates/dxl/operators/CDXLPhysicalIndexOnlyScan.h"
#include "naucrates/dxl/parser/CParseHandlerFactory.h"
#include "naucrates/dxl/parser/CParseHandlerFilter.h"
#include "naucrates/dxl/parser/CParseHandlerIndexCondList.h"
#include "naucrates/dxl/parser/CParseHandlerIndexDescr.h"
#include "naucrates/dxl/parser/CParseHandlerProjList.h"
#include "naucrates/dxl/parser/CParseHandlerProperties.h"
#include "naucrates/dxl/parser/CParseHandlerScalarOp.h"
#include "naucrates/dxl/parser/CParseHandlerTableDescr.h"
#include "naucrates/dxl/parser/CParseHandlerUtils.h"

using namespace spqdxl;

XERCES_CPP_NAMESPACE_USE

//---------------------------------------------------------------------------
//    @function:
//        CParseHandlerShareIndexScan::CParseHandlerShareIndexScan
//
//    @doc:
//        Ctor
//
//---------------------------------------------------------------------------
CParseHandlerShareIndexScan::CParseHandlerShareIndexScan(
    CMemoryPool *mp, CParseHandlerManager *parse_handler_mgr,
    CParseHandlerBase *parse_handler_root)
    : CParseHandlerPhysicalOp(mp, parse_handler_mgr, parse_handler_root),
      m_index_scan_dir(EdxlisdSentinel)
{
}

//---------------------------------------------------------------------------
//    @function:
//        CParseHandlerShareIndexScan::StartElement
//
//    @doc:
//        Invoked by Xerces to process an opening tag
//
//---------------------------------------------------------------------------
void
CParseHandlerShareIndexScan::StartElement(const XMLCh *const,  // element_uri,
                                     const XMLCh *const element_local_name,
                                     const XMLCh *const,  // element_qname
                                     const Attributes &attrs)
{
    StartElementHelper(element_local_name, attrs, EdxltokenPhysicalShareIndexScan);
}

//---------------------------------------------------------------------------
//    @function:
//        CParseHandlerShareIndexScan::EndElement
//
//    @doc:
//        Invoked by Xerces to process a closing tag
//
//---------------------------------------------------------------------------
void
CParseHandlerShareIndexScan::EndElement(const XMLCh *const,    // element_uri,
                                   const XMLCh *const element_local_name,
                                   const XMLCh *const  // element_qname
)
{
    EndElementHelper(element_local_name, EdxltokenPhysicalShareIndexScan);
}

//---------------------------------------------------------------------------
//    @function:
//        CParseHandlerShareIndexScan::StartElementHelper
//
//    @doc:
//        Common StartElement functionality for ShareIndexScan and IndexOnlyScan
//
//---------------------------------------------------------------------------
void
CParseHandlerShareIndexScan::StartElementHelper(
    const XMLCh *const element_local_name, const Attributes &attrs,
    Edxltoken token_type)
{
    if (0 != XMLString::compareString(CDXLTokens::XmlstrToken(token_type),
                                      element_local_name))
    {
        CWStringDynamic *str = CDXLUtils::CreateDynamicStringFromXMLChArray(
            m_parse_handler_mgr->GetDXLMemoryManager(), element_local_name);
        SPQOS_RAISE(spqdxl::ExmaDXL, spqdxl::ExmiDXLUnexpectedTag,
                   str->GetBuffer());
    }

    // get the index scan direction from the attribute
    const XMLCh *index_scan_direction = CDXLOperatorFactory::ExtractAttrValue(
        attrs, EdxltokenIndexScanDirection, token_type);
    m_index_scan_dir = CDXLOperatorFactory::ParseIndexScanDirection(
        index_scan_direction, CDXLTokens::GetDXLTokenStr(token_type));
    SPQOS_ASSERT(EdxlisdSentinel != m_index_scan_dir);

    // create and activate the parse handler for the children nodes in reverse
    // order of their expected appearance

    CParseHandlerBase *table_descr_parse_handler =
        CParseHandlerFactory::GetParseHandler(
            m_mp, CDXLTokens::XmlstrToken(EdxltokenTableDescr),
            m_parse_handler_mgr, this);
    m_parse_handler_mgr->ActivateParseHandler(table_descr_parse_handler);

    // parse handler for the index descriptor
    CParseHandlerBase *index_descr_parse_handler =
        CParseHandlerFactory::GetParseHandler(
            m_mp, CDXLTokens::XmlstrToken(EdxltokenIndexDescr),
            m_parse_handler_mgr, this);
    m_parse_handler_mgr->ActivateParseHandler(index_descr_parse_handler);

    // parse handler for the index condition list
    CParseHandlerBase *index_condition_list_parse_handler =
        CParseHandlerFactory::GetParseHandler(
            m_mp, CDXLTokens::XmlstrToken(EdxltokenScalarIndexCondList),
            m_parse_handler_mgr, this);
    m_parse_handler_mgr->ActivateParseHandler(
        index_condition_list_parse_handler);

    // parse handler for the filter
    CParseHandlerBase *filter_parse_handler =
        CParseHandlerFactory::GetParseHandler(
            m_mp, CDXLTokens::XmlstrToken(EdxltokenScalarFilter),
            m_parse_handler_mgr, this);
    m_parse_handler_mgr->ActivateParseHandler(filter_parse_handler);

    // parse handler for the proj list
    CParseHandlerBase *proj_list_parse_handler =
        CParseHandlerFactory::GetParseHandler(
            m_mp, CDXLTokens::XmlstrToken(EdxltokenScalarProjList),
            m_parse_handler_mgr, this);
    m_parse_handler_mgr->ActivateParseHandler(proj_list_parse_handler);

    //parse handler for the properties of the operator
    CParseHandlerBase *prop_parse_handler =
        CParseHandlerFactory::GetParseHandler(
            m_mp, CDXLTokens::XmlstrToken(EdxltokenProperties),
            m_parse_handler_mgr, this);
    m_parse_handler_mgr->ActivateParseHandler(prop_parse_handler);

    // store parse handlers
    this->Append(prop_parse_handler);
    this->Append(proj_list_parse_handler);
    this->Append(filter_parse_handler);
    this->Append(index_condition_list_parse_handler);
    this->Append(index_descr_parse_handler);
    this->Append(table_descr_parse_handler);
}

//---------------------------------------------------------------------------
//    @function:
//        CParseHandlerShareIndexScan::EndElementHelper
//
//    @doc:
//        Common EndElement functionality for ShareIndexScan and IndexOnlyScan
//
//---------------------------------------------------------------------------
void
CParseHandlerShareIndexScan::EndElementHelper(const XMLCh *const element_local_name,
                                         Edxltoken token_type)
{
    if (0 != XMLString::compareString(CDXLTokens::XmlstrToken(token_type),
                                      element_local_name))
    {
        CWStringDynamic *str = CDXLUtils::CreateDynamicStringFromXMLChArray(
            m_parse_handler_mgr->GetDXLMemoryManager(), element_local_name);
        SPQOS_RAISE(spqdxl::ExmaDXL, spqdxl::ExmiDXLUnexpectedTag,
                   str->GetBuffer());
    }

    // construct node from the created child nodes
    CParseHandlerProperties *prop_parse_handler =
        dynamic_cast<CParseHandlerProperties *>((*this)[0]);
    CParseHandlerProjList *proj_list_parse_handler =
        dynamic_cast<CParseHandlerProjList *>((*this)[1]);
    CParseHandlerFilter *filter_parse_handler =
        dynamic_cast<CParseHandlerFilter *>((*this)[2]);
    CParseHandlerIndexCondList *index_condition_list_parse_handler =
        dynamic_cast<CParseHandlerIndexCondList *>((*this)[3]);
    CParseHandlerIndexDescr *index_descr_parse_handler =
        dynamic_cast<CParseHandlerIndexDescr *>((*this)[4]);
    CParseHandlerTableDescr *table_descr_parse_handler =
        dynamic_cast<CParseHandlerTableDescr *>((*this)[5]);

    CDXLTableDescr *dxl_table_descr =
        table_descr_parse_handler->GetDXLTableDescr();
    dxl_table_descr->AddRef();

    CDXLIndexDescr *dxl_index_descr =
        index_descr_parse_handler->GetDXLIndexDescr();
    dxl_index_descr->AddRef();

    CDXLPhysical *dxl_op = nullptr;
    if (EdxltokenPhysicalIndexOnlyScan == token_type)
    {
        dxl_op = SPQOS_NEW(m_mp) CDXLPhysicalIndexOnlyScan(
            m_mp, dxl_table_descr, dxl_index_descr, m_index_scan_dir);
        m_dxl_node = SPQOS_NEW(m_mp) CDXLNode(m_mp, dxl_op);
    }
    else
    {
        SPQOS_ASSERT(EdxltokenPhysicalShareIndexScan == token_type);
        dxl_op = SPQOS_NEW(m_mp) CDXLPhysicalShareIndexScan(
            m_mp, dxl_table_descr, dxl_index_descr, m_index_scan_dir);
        m_dxl_node = SPQOS_NEW(m_mp) CDXLNode(m_mp, dxl_op);
    }


    // set statistics and physical properties
    CParseHandlerUtils::SetProperties(m_dxl_node, prop_parse_handler);

    // add children
    AddChildFromParseHandler(proj_list_parse_handler);
    AddChildFromParseHandler(filter_parse_handler);
    AddChildFromParseHandler(index_condition_list_parse_handler);

    // deactivate handler
    m_parse_handler_mgr->DeactivateHandler();
}

// EOF
